package com.dxy.common.utils;

import com.alibaba.fastjson.JSON;
import com.dxy.common.exp.ServiceException;
import com.dxy.common.properties.JWTConfigProperties;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Slf4j
@Component
public class JwtUtil {

    private static JWTConfigProperties jwtConfigProperties;

    @Autowired
    public JwtUtil(JWTConfigProperties jwtConfigProperties) {
        JwtUtil.jwtConfigProperties = jwtConfigProperties;
    }

    public static final String TOKEN_NAME = "token";// token名称
    private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//签名算法

    public static SecretKey generateKey() {
        String secret = jwtConfigProperties.getSecret();
        if (StringUtils.isBlank(secret)) {
            throw new ServiceException("secret can not be null！");
        }
        byte[] encodeKey = Base64.decodeBase64(Base64.encodeBase64(secret.getBytes()));
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");// 获取加密key
    }


    public static String createToken(String uniqueId, Object subject) {
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + jwtConfigProperties.getExpire() * 1000);
        Map<String, Object> header = new HashMap<>();
        header.put("typ", "JWT");
        header.put("alg", "HS256");
        Map<String, Object> claims = new HashMap<>();
        claims.put("module", jwtConfigProperties.getModule());
        claims.put("author", jwtConfigProperties.getAuthor());
        claims.put("site", jwtConfigProperties.getSite());
        claims.put("user", uniqueId);
        JwtBuilder jwtBuilder = Jwts.builder()
                .setHeader(header)//保存头信息
                .setClaims(claims)//保存附加数据
                .setId(UUID.randomUUID().toString().replace("-", ""))
                .setIssuedAt(nowDate)//签发时间
                .setIssuer(jwtConfigProperties.getIssuer())//设置签发者
                .setSubject(JSON.toJSONString(subject))//此处可以设置要传递的数据
                .signWith(signatureAlgorithm, generateKey())//设置签名算法
                .setExpiration(expireDate);//配置失效时间
        return jwtBuilder.compact();
    }

    public static Jws<Claims> parseToken(String token) {
        try {
            return Jwts.parser().setSigningKey(generateKey()).parseClaimsJws(token);
        } catch (JwtException e) {
            e.printStackTrace();
            throw new ServiceException(401, "token error");
        }
    }

    public static boolean verifyToken(String token) {
        Jws<Claims> jws = parseToken(token);
        return jws != null;//没有异常就返回true
    }

    public static String refreshToken(String token) {
        return createToken(getUniqueId(token), getSubject(token));
    }


    public static String getUniqueId(String token) {
        Jws<Claims> jws = parseToken(token);
        return jws.getBody().get("user", String.class);
    }

    public static Object getSubject(String token) {
        Jws<Claims> jws = parseToken(token);
        return JSON.parse(jws.getBody().getSubject());
    }

    public static <T> T getSubject(String token, Class<T> clazz) {
        Jws<Claims> jws = parseToken(token);
        return JSON.parseObject(jws.getBody().getSubject(), clazz);
    }
}
